CDNキャッシュ向けレスポンスヘッダーCache-Control:s-maxage を触ってみた
CDNやプロキシといった共有キャッシュ向けにキャッシュの保持期間を制御する Cache-Control: s-maxage=seconds
というレスポンスヘッダーが存在します。
ブラウザとCDNでキャッシュの保持期間を分けたい時や、マルチCDNの構成においてオリジン側でCDNのキャッシュの保持期間を一元管理したい時などに重宝します。
本記事では、この共有キャッシュ向けレスポンスヘッダーについて、かんたんに紹介します。
ブラウザ向けの max-ageと共有キャッシュ向けの s-max-age
s-maxage
によく似たディレクティブに max-age
があります。どちらも Cache-Control
と一緒に用いますが、用途は少し異なります。
max-age
はCDNやプロキシといった共有キャッシュ、及び、クライアント向けのキャッシュ設定です。
s-maxage
は共有キャッシュに特化したキャッシュ設定であり、max-age
/ Expires
よりも優先されます(上書きます)。その上で、CDN によって、CDN設定とs-maxage
のどちらのキャッシュ時間を優先するか決まります。
s-maxage
の綴りは s-max-age
ではないので、ご注意ください。
CloudFront と Cache-Control:max-age, s-maxage の連携
CDN に Amazon CloudFront を用いているケースにおいて、max-age
と s-maxage
の値によって CDN(エッジ)ではどのようにキャッシュされるのでしょうか。
CloudFrontのキャッシュポリシーにデフォルトの Managed-CachingOptimized
を設定している場合で確認します。
このポリシーは次の通りです。
- Minimum TTL : 1
- Maximum TTL : 31536000
- Default TTL : 86400
※ Minimum TTL=0 の場合、下記ルールとは異なります。詳細はドキュメントを参照してください。
max-ageもs-maxageも未設定の場合
オリジンが max-age
も s-maxage
も返さない場合、
- CloudFront は Default TTL の期間だけキャッシュ保持(厳密には MinimumとDefaultの大きい方)
- クライアントのキャッシュ期間はブラウザ依存
max-ageは設定されていてs-maxageは未設定の場合
オリジンが max-age
を返し s-maxage
は返さない場合、
- CloudFront は Minimum TTL/Maximum TTL/
max-age
の中から、2番めに大きい値だけキャッシュ。例えば Minimum <max-age
< Maximum の場合、max-age
の期間だけキャッシュ - クライアントは
max-age
の期間だけキャッシュ
max-ageとs-maxageの両方が設定されている場合
オリジンが max-age
とs-maxage
の両方を返す場合、
- CloudFront は
max-age
よりもs-maxage
を優先し、Minimum TTL/Maximum TTL/s-maxage
の中から、2番めに大きい値だけキャッシュ。例えば Minimum <s-maxage
< Maximum の場合、s-maxage
の期間だけキャッシュ - クライアントは
max-age
の期間だけキャッシュ
S3 がオリジンの場合に s-maxage を確認
CloudFront のオリジンに S3 を設定し、s-maxage
の挙動を確認します。
CloudFront のキャッシュポリシーを Managed-CachingOptimized
に設定し、S3オブジェクトのメタデータで Cache-Control
を設定します。
Cache-Control: s-maxage=300,max-age=180
の場合、 Minimum TTL(=1) < s-maxage(=300) < Maximum TTL(= 31536000)
のため、エッジでは s-maxage
で指定した秒数だけキャッシュされるはずです。
初回アクセス時
初回アクセス時には キャッシュミスします。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 14 Connection: keep-alive Date: Wed, 20 Jan 2021 15:29:10 GMT Last-Modified: Wed, 20 Jan 2021 15:09:33 GMT ETag: "910c8bc73110b0cd1bc5d2bcae782511" Cache-Control: s-maxage=300,max-age=180 Accept-Ranges: bytes Server: AmazonS3 X-Cache: Miss from cloudfront ...
キャッシュ期間内の2度目のアクセス
290秒後にアクセスします(max-age
< 290 < s-maxage
)。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 14 Connection: keep-alive Date: Wed, 20 Jan 2021 15:29:10 GMT Last-Modified: Wed, 20 Jan 2021 15:09:33 GMT ETag: "910c8bc73110b0cd1bc5d2bcae782511" Cache-Control: s-maxage=300,max-age=180 Accept-Ranges: bytes Server: AmazonS3 X-Cache: Hit from cloudfront Via: 1.1 53767392640cf5282c1ce18d7cc7b0e1.cloudfront.net (CloudFront) X-Amz-Cf-Pop: HAM50-C1 X-Amz-Cf-Id: r4CPRg6eZDjv25BWIjwjYvbvkwCMNJRhQYB33AAoWLMy4MTKMzVO4g== Age: 290
CloudFront では s-maxage
の時間だけキャッシュされているので、キャッシュヒットします。
エッジキャッシュのstale後のアクセス
エッジキャッシュが stale になったあとにアクセスします。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 14 Connection: keep-alive Last-Modified: Wed, 20 Jan 2021 15:09:33 GMT Accept-Ranges: bytes Server: AmazonS3 Date: Wed, 20 Jan 2021 15:34:10 GMT Cache-Control: s-maxage=300,max-age=180 ETag: "910c8bc73110b0cd1bc5d2bcae782511" X-Cache: RefreshHit from cloudfront ...
X-Cache: RefreshHit from cloudfront
から、エッジキャッシュが stale なので、オリジンにアクセスしていることがわかります。
オリジンS3バケットのサーバーアクセスロギングから対応するログを確認すると、この RefreshHit
のリクエスト(conditional GET)に対して 304: Not Modified
を返していました。
008600d... BUCKET-NAME [20/Jan/2021:15:34:09 +0000] 130.***.***.*** - ERXXX REST.GET.OBJECT s-maxage.html "GET /s-maxage.html HTTP/1.1" 304 - - 14 9 - "-" "curl/7.64.1" - Ng...= - - - BUCKET-NAME.s3.amazonaws.com -
s-maxageとSurrogate-Control ヘッダーとの違いは?
Cache-Control: s-maxage
ディレクティブと同様の機能を一部のCDNベンダーは Surrogate-Control
ヘッダーで提供しています。
Surrogate-Control
は Cache-Control
の エッジ版であり、W3C の 2001年版の Edge Architecture Specificationにも確認できます。
実際の仕様はベンダー・ミドルウェアによって細部が異なります。
例えばFastly の場合、エッジキャッシュの保持期間に関してCache-Control: s-maxage=3600
とSurrogate-Control: max-age=3600
は同じであり、Surrogate-Control
ヘッダーはオリジン-CDN間でのみ利用され、クライアント向けレスポンスからは除外される点がCache-Control
と異なります。
参考 : Configuring caching | Fastly Help Guides
Surrogate-Control のCDN向け 統一規格 CDN-Cache-Control レスポンスヘッダー のドラフトが公開中
CDN に特化した統一的なキャッシュヘッダーがほしいということで、CDN-Cache-Control
という新しいレスポンスヘッダーのドラフトが 2020年11月に公開されました。
The CDN-Cache-Control HTTP Response Header Field
Cache-Control
の仕様はすでに十分すぎるくらいに複雑で拡張が難しく、CDNだけでなくプロキシも含めた共有キャッシュが対象であること、Surrogate-Control
はベンダーごとに独自仕様となっていて、互換性を維持したまま拡張するのが難しいことから、新しいヘッダーを用意することになったようです。
マルチCDN環境でCDNのキャッシュ設定を一元管理できる未来を期待したい一方で、ドラフトによると "Individual CDNs can choose to define their own control mechanisms that take precedence over this header field."とあるので、厳しい現実を突きつけられる可能性もあります。
このドラフトの著者は Akamai/Fastly/Cloudflare の CDN ベンダーから構成されています。
著者の一人 Mark Nottingham さんは Surrogate-Control
を定義した W3C Note 04 August 2001 版 Edge Architecture Specification の著者の一人でもあります。
まとめ
CDNのキャッシュを制御するには、CDN本体の設定だけでなく、オリジンのレスポンスヘッダー(Cache-Control: s-maxage
/Surrogate-Control
)でも制御できます。
設定が分散していると挙動を把握するのが難しくなるため、まずは CDN 単体でキャッシュ設定することをおすすめします。
最大の疑問点、s-maxage
の綴りがs-max-age
でない理由については、最後までわかりませんでした。
それでは。
参考
- Cache-Control - HTTP | MDN
- Managing how long content stays in the cache (expiration) - Amazon CloudFront
- Request and Response Behavior for Amazon S3 Origins - Amazon CloudFront
- CDNのキャッシュを制御する CDN-Cache-Control ヘッダ - ASnoKaze blog
- IETF Draft : The CDN-Cache-Control HTTP Response Header Field
- W3C : Edge Architecture Specification 1.0
- Content delivery networks (CDNs) - web.dev
- Controlling caching | Fastly Help Guides
- 渋川 よしき 『Real World HTTP 第2版』 13.4節 CDN(Content Delivery Network)